/*
 * This app starts a very simple shell and executes some simple commands.
 * The commands are stored in the hostfs_root/shellrc
 * The shell loads the file and executes the command line by line.
 */
#include "user_lib.h"
#include "string.h"
#include "util/types.h"

#define PGSIZE 4096
#define streql(s1, s2) (strcmp(s1, s2) == 0)
#define Switch(s) if(0){}
#define Case(s) else if(streql(cmd, s))
#define Default() else

// int shell_main(int argc, char *argv[]);
int shell_exec(char *cmd, char *arg, char *tmp);

int main(int argc, char *argv[])
{

	printu("\n======== Shell Start ========\n\n");
	char *buf = naive_malloc();
	char *cmd = naive_malloc();
	char *arg = naive_malloc();
	char *tmp = naive_malloc();

	strcpy(cmd, "app_shellrc");
	strcpy(arg, "");
	shell_exec(cmd, arg, tmp);

	change_cwd("/RAMDISK0");

	while (1)
	{
		read_cwd(tmp);
		printu("\nhxy@riscv-pke-challengex: %s", tmp);
		printu("\n===>$ ");
		getstring_u(buf, PGSIZE); // 等待用户输入

		char *token = strtok(buf, " ");
		if (token == NULL)
			continue;
		strcpy(cmd, token);

		token = strtok(NULL, " ");
		strcpy(arg, token == NULL ? "" : token);

		int ret = shell_exec(cmd, arg, tmp);
		if (ret != 0) 
			break;
	}

	naive_free(buf);
	naive_free(cmd);
	naive_free(arg);
	naive_free(tmp);
	printu("\n======== Shell End ========\n\n");
	exit(0);
	return 0;
}

int shell_exec(char *cmd, char *arg, char *tmp)
{
	Switch(cmd)
	Case("exit") { return 1; }
	Case("pwd") { read_cwd(tmp); printu("%s\n", tmp); }
	Case("ls") {
		int dir_fd = opendir_u(arg);
		if (dir_fd < 0) { printu("ls error: directory not found\n"); return 0; }
		struct dir dir;
		int width = 20;
		while (readdir_u(dir_fd, &dir) == 0) {
			for (int i = strlen(dir.name); i < width; i++) dir.name[i] = ' ';
			dir.name[width] = '\0';
			printu("%s inum=%d, type=%s, size=%d\n", 
				dir.name, dir.inum, dir.type == FILE_I ? "FILE" : dir.type == DIR_I ? "DIR " : "UNKNOWN", dir.size);
		}
		closedir_u(dir_fd);
	}
	Case("cd") {
		int ret = change_cwd(arg);
		if (ret == -1) printu("chdir error: path not found\n");
		else if (ret == -2) printu("chdir error: this is not a directory\n");
	}
	Case("echo") { printu(arg); }
	Case("help") { printu(""
		"exit: exit the shell\n"
		"help: print this help message\n"
		"ls: list files in current directory\n"
		"pwd: print current working directory\n"
		"cd: change current working directory\n"
		"echo: print string\n"
	);}
	Default() {
		// 在/bin目录下查找
		if (cmd[0] != '/') {
			strcpy(tmp, "/bin/");
			strcat(tmp, cmd);
			strcpy(cmd, tmp);
		}
		int fd = open(cmd, O_RDONLY);
		if (fd == -1) {
			printu("command not found\n");
			return 0;
		}
		close(fd);
		int pid = fork();
		if (pid == 0) {
			int ret = exec(cmd, arg);
			if (ret == -1) printu("exec error\n");
		}
		else {
			wait(pid);
		}
	}
	return 0;
}
